#!/bin/sh
# Backport Debian source packages for Xapian.
#
# Copyright (C) 2004 Richard Boulton
# Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2015,2016,2017,2018,2019 Olly Betts
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
# USA

# Dependencies:
# dch from package devscripts.

set -e

MIRROR=http://httpredir.debian.org/debian/

DEBIAN_CODENAMES='buster stretch jessie'
UBUNTU_CODENAMES='disco bionic xenial trusty'
UBUNTU_FIRST=`echo "$UBUNTU_CODENAMES"|sed 's/.* //'`

V_OPT=
BUILD_INT=1
HELP_RC=
while true ; do
  case $1 in
  -v)
    V_OPT="$1$2"
    shift
    ;;
  -v*)
    V_OPT=$1
    ;;
  -b)
    BUILD_INT=$2
    shift
    ;;
  -b*)
    BUILD_INT=`expr substr "$1" 3 9999`
    ;;
  --help)
    HELP_RC=0
    break
    ;;
  -*)
    HELP_RC=1
    break
    ;;
  *)
    break
    ;;
  esac
  shift
done

if [ -n "$HELP_RC" -o $# -lt 2 ] ; then
  echo "Usage: $0 [-v <last backported version>] [-b <backport #>] SOURCE_PKG VERSION [CODENAME...]"
  echo
  echo "e.g.: $0 xapian-core 1.4.11-1 xenial"
  echo 'If no codenames are specified, the default is to backport for all of them.'
  echo
  echo "Currently, the recognised values are:"
  echo "    $DEBIAN_CODENAMES"
  echo "    $UBUNTU_CODENAMES"
  echo "And the magic values which expand to the above lists:"
  echo "    debian ubuntu"
  exit ${HELP_RC:-1}
fi

# Remove any backport suffix from any -v option.
V_OPT=`printf '%s' "$V_OPT"|sed 's/~bpo.*//'`
PKG=$1
VERSION=$2
shift
shift

SUFFIX=`echo "$VERSION"|sed 's/.*-/-/'`
VERSION=`echo "$VERSION"|sed 's/-[^-]*$//'`

# Debian/Ubuntu codename or codenames to build for.
# This will be overridden by the command line arguments, if any were passed.
CODENAMES="$DEBIAN_CODENAMES $UBUNTU_CODENAMES"

# Options to pass to dpkg-buildpackage when building source packages
BUILDPACKAGE_SRC_OPTS="-us -uc -d -S $V_OPT --changes-option=-DBinary=dummy"

# Add entry to changelog if we're backporting.
adjust_changelog() {
  if [ sid != "$CODENAME" ] ; then
    base_version=`dpkg-parsechangelog|sed 's/^Version: //p;d'`
    backport_version=$base_version$BACKPORT_SUFFIX
    # --force-bad-version needed for backporting, since the "new" version may
    # be less than the "old".  Direct stdin from /dev/null to prevent dch
    # stopping to confirm the bad version is OK.
    if [ 1 = "$ubuntu" ] ; then
      distribution=$CODENAME
    elif [ "`echo "$DEBIAN_CODENAMES"|cut -d' ' -f1`" = "$CODENAME" ] ; then
      # Backport for the most recent stable debian release.
      distribution=$CODENAME-backports
    else
      distribution=$CODENAME-backports-sloppy
    fi
    dch --force-bad-version -v "$backport_version" -D "$distribution" \
	"Rebuild for $CODENAME backports." < /dev/null
  fi
}

build_it() {
  adjust_changelog

  overrides=
  case $PKG:$CODENAME:$VERSION in
    xapian-bindings:jessie:*)
      # Make sure we add python-xapian to debian/control.
      overrides='PYTHON_VERSIONS=dummy' ;;
    xapian-bindings:trusty:*)
      # Make sure we add python-xapian and python3-xapian to debian/control.
      overrides='PYTHON_VERSIONS=dummy PYTHON3_VERSIONS=dummy' ;;
    xapian-bindings:stretch:*|xapian-bindings:xenial:*)
      # Make sure we add python-xapian and python3-xapian to debian/control.
      overrides='PYTHON_VERSIONS=dummy PYTHON3_VERSIONS=dummy RUBY_VERSIONS=2.3 RUBY_PROVIDES="X-Dummy: No provides"' ;;
    xapian-bindings:*:*)
      # Make sure we add python-xapian and python3-xapian to debian/control.
      overrides='PYTHON_VERSIONS=dummy PYTHON3_VERSIONS=dummy RUBY_VERSIONS=2.5 RUBY_PROVIDES="X-Dummy: No provides"' ;;
  esac

  # libxapian30 (i.e. 1.4.x) is built with C++ "v5" ABI in stretch and newer
  # and in xenial and newer, so append "v4" to the soname for backports to
  # older versions so upgrades with the backport installed work cleanly.
  case $PKG:$VERSION in
  xapian-core:1.4.*)
    case $CODENAME in
    jessie|trusty)
      perl -i -e 'while (<>) { print; last if /^libxapian_soversion:=/ } while (<>) { print; last unless /\\$/ } print "libxapian_soversion:=\$(libxapian_soversion)v4\n"; while (<>) { s/^(\techo .libxapian.*)>/$1|sed "s,v4,,g" >/; print }' debian/rules
      sed -i 's/^\(Package: libxapian@LIBXAPIAN_SOVERSION@\)\(.*\)/\1\2\nConflicts: libxapian30\2\nReplaces: libxapian30\2/' debian/control.in
      dch -a 'debian/control.in,debian/rules: Add v4 suffix to soname. (Closes: #863705)'
      ;;
    esac
    ;;
  esac

  # Mainly for Survex.
  case $CODENAME in
      trusty|xenial|jessie|stretch)
	if grep -q libwxgtk3.0-gtk3-dev debian/control ; then
	    sed -i 's/libwxgtk3.0-gtk3-dev/libwxgtk3.0-dev/g' debian/control
	    dch -a 'debian/control: Build with GTK2 version of wxWidgets.'
	fi
	;;
  esac

  case $CODENAME in
      jessie)
	if [ "`cat debian/compat`" -gt 10 ] ; then
	    echo 10 > debian/compat
	    sed -i 's/debhelper (>= [^)]*)/debhelper (>= 10)/' debian/control
	    dch -a 'debian/control: Lower debhelper compat level to 10.'
	fi
	;;
      trusty|xenial)
	if [ "`cat debian/compat`" -gt 9 ] ; then
	    echo 9 > debian/compat
	    sed -i 's/debhelper (>= [^)]*)/debhelper (>= 9)/' debian/control
	    dch -a 'debian/control: Lower debhelper compat level to 9.'
	    # Compat 9 doesn't default to parallel building.
	    if grep -q 'dh_auto_test --no-parallel' debian/rules ; then
		sed -i 's/dh_auto_test --no-parallel/dh_auto_test/' debian/rules
		dch -a 'debian/rules: Drop --no-parallel from dh_auto_test invocation (debhelper compat level 9 does not default to parallel building).'
	    fi
	fi
	;;
  esac

  case `grep -c '^[^#]*\<CODENAME\>' debian/rules` in
    '')
      echo 'Failed to grep debian/rules'
      exit 1
      ;;
    [01])
      # Run maintclean and maint targets, if they exist.
      fakeroot debian/rules maintclean || true
      eval fakeroot debian/rules maint $overrides || true
      ;;
    *)
      # If debian/rules has at least two non-commented out references to
      # CODENAME then create debian/codename.
      echo "$CODENAME" > debian/codename
      # Generates control from control.in (and maybe other files).
      fakeroot debian/rules maintclean CODENAME="$CODENAME"
      eval fakeroot debian/rules maint CODENAME="$CODENAME" $overrides
      ;;
  esac

  include_src_opt=
  case $backport_version in
    *99$UBUNTU_FIRST+1)
      # We don't really want to upload the orig tarball for all Ubuntu
      # backports, only if it isn't already in the archive.  So for now, just
      # upload it for the first codename in alphabetical order, and only if
      # the BUILD_INT (N in the +N suffix) is 1.
      include_src_opt=-sa ;;
  esac
  debuild ${BUILDPACKAGE_SRC_OPTS} $include_src_opt

  if [ 1 != "$ubuntu" ] ; then
    # Debian
    echo "cd build && sbuild --debbuildopt=$V_OPT -d $CODENAME-backports ${PKG}_$backport_version.dsc"
  fi
}

# Get the codename(s) specified by the user.
if [ -n "$*" ] ; then
  CODENAMES=`echo "$*"|sed 's/\<debian\>/'"$DEBIAN_CODENAMES"'/;s/\<ubuntu\>/'"$UBUNTU_CODENAMES"'/'`
fi

ubuntu=0
for CODENAME in $CODENAMES ; do
  # Check that the codename is known.
  DEBIAN_CODENAMES_RE='\('`echo "$DEBIAN_CODENAMES"|sed 's/ /\\\|/g'`'\)$'
  UBUNTU_CODENAMES_RE='\('`echo "$UBUNTU_CODENAMES"|sed 's/ /\\\|/g'`'\)$'
  if expr "$CODENAME" : "$DEBIAN_CODENAMES_RE" >/dev/null ; then
    echo "Making source packages for $CODENAME"
    if [ -z "$V_OPT" ] ; then
      echo 'You need to specify -v<last backported version> for debian backports'
      exit 1
    fi
  elif expr "$CODENAME" : "$UBUNTU_CODENAMES_RE" >/dev/null ; then
    echo "Making source packages for $CODENAME"
    ubuntu=1
  else
    echo "Codename \"$CODENAME\" not known."
    echo "Known codenames are: $DEBIAN_CODENAMES $UBUNTU_CODENAMES"
    exit 1
  fi

trap "echo \"backport-source-packages failed\"" EXIT

# $BACKPORT_SUFFIX holds a suffix to be added to the debian version number for
# the backport.

# We need to add a suffix to the debian version number for the backported
# package to avoid conflicts with the package in unstable.
# For Ubuntu we add ".99$CODENAME" since it should sort
# before any other modification (and since dapper, Ubuntu codenames are
# allocated alphabetically).  To handle the wrapping from zesty to artful,
# we add ".999$CODENAME" for artful and later.  For Debian releases, we use
# backports.org-compatible package versions - e.g. we append "~bpo8+1" for
# Debian 8 (jessie) (and a suffix starting "~" sorts as less than no suffix).
case $CODENAME in
buster)
  BACKPORT_SUFFIX="~bpo10+$BUILD_INT" ;;
stretch)
  BACKPORT_SUFFIX="~bpo9+$BUILD_INT" ;;
jessie)
  BACKPORT_SUFFIX="~bpo8+$BUILD_INT" ;;
*)
  if [ x"$ubuntu" = x0 ] ; then
    echo "Debian codename '$CODENAME' not mapped to a ~bpoN suffix"
    exit 1
  fi
  case $CODENAME in
  trusty|xenial)
    BACKPORT_SUFFIX=".99$CODENAME+$BUILD_INT" ;;
  *)
    BACKPORT_SUFFIX=".999$CODENAME+$BUILD_INT" ;;
  esac
  ;;
esac

# Unpack distribution tarballs, and put the debian control files into place,
# and build source packages
mkdir -p build
cd build
  case $PKG in
  lib*) DIR=`echo $PKG|cut -c1,2,3,4` ;;
  *) DIR=`echo $PKG|cut -c1` ;;
  esac
  DSC=${PKG}_$VERSION$SUFFIX.dsc
  if [ -f "$DSC" ] ; then
    [ -d backup ] || mkdir backup
    if ! mv "$DSC" backup ; then
      # Handle dsc being hardlinked into backup already.
      cmp "$DSC" "backup/$DSC" && rm -f "$DSC"
    fi
    dget -b "file://`pwd`/backup/$DSC"
  elif [ -f "../$DSC" ] ; then
    dget -b "file://`cd .. && pwd`/$DSC"
  else
    dget "${MIRROR}pool/main/$DIR/$PKG/$DSC"
  fi
  cd ${PKG}-${VERSION}
    build_it
  cd ..
  rm -rf ${PKG}-${VERSION}
cd ..

echo "Backported ${PKG} ${VERSION} for $CODENAME successfully"
done

trap - EXIT
